
#include "main.h"
// #include "stm32h7xx_hal.h"
#include "cmsis_os.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "adc.h"
#include "spi.h"
// #include "stm32f407xx.h"

#include <stdio.h>
#include <string.h>

#include "../Lily/Lily_help.h"
#include "core.h"

#include "../Hardware/LCD/lcd.h"
#include "../Hardware/TOUCH/touch.h"
#include "../Hardware/sys/delay.h"

#include "Julianna.h"

#include "activities.h"
#include "TextBox.h"
#include "Juli_chart.h"
#include "EditTextBox.h"

#include "stm32f4xx_hal_uart.h"

int rx_monitor(void);
void init_flash(void);
char need_power_off = 0; // 0 power on, 1
int power_off_peroid = 30;
int power_off_timer(void);

int screen_lock = 0;
int video_mode = 0;

#define dma_buffer_len 255
char dma_tx1[dma_buffer_len + 1], dma_tx2[dma_buffer_len + 1], dma_now_write_at = 0, dma_now_count = 0;
volatile char dma_send_done = 1;
float beep_volume = 0.2f;
int beep_max_volume = 1000;

Pipe UART1Tx_pipe, UART1Rx_pipe;
Pipe UART2Tx_pipe, UART2Rx_pipe;
Pipe UART3Tx_pipe, UART3Rx_pipe;

void init_core()
{
	// lily tick
	// HAL_TIM_Base_Start(&htim2); //1MHz
	// HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
	HAL_TIM_Base_Start_IT(&htim6); //timer2 start int, 168Hz

	HAL_TIM_Base_Start(&htim2);
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
	__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 0);
	__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //receive interrupt -> bluetooth
	// __HAL_UART_ENABLE_IT(&huart6, UART_IT_RXNE); // -> screen
	// __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //
	// __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);  //idle interrupt
	// adc_raw_val = ads[0];
	// HAL_ADC_Start(&hadc1);

	// HAL_UART_Transmit(&huart1, "DIR(1)\r\n", 8, 10);
	// public_a_fun_link_n("clc", LCD_clear, 0);
	// LCD_SSD_BackLightSet((u8)bl);
	public_a_fun_link_int("bl", LCD_SSD_BackLightSet, 1);
	// public_a_cmd_link("secho", echo_to_screen);
	public_a_cmd_link("io", gpio_cmd);
	// LCD_clear();
	public_a_timer(blink, Hz(4));

	// public_a_fun_link_n("listen", start_listen_adc, 0);
	// public_a_fun_link_n("stplisn", stop_listen_adc, 0);
	delay_init(168);
	LCD_Init(); //初始化LCD
	TP_Init();
	init_julianna();

	LCD_SSD_BackLightSet(27);
	// float t1 = millisf();
	// LCD_Clear(BACK_COLOR);
	LCD_changeSize(24);

	// public_a_fun_link_int("spi", start_spi_rec, 0);
	// public_a_fun_link_int("stop", stop_spi, 0);
	public_a_fun_link_int("bl", LCD_SSD_BackLightSet, 1);
	public_a_fun_link_n("beep", beep, 2);
	// public_a_var_ref("tb", &fever_temprature, 'f');
	// public_a_var_ref("tw", &alarm_water_temprature, 'f');
	public_a_var_ref("volume", &beep_volume, 'f');
	//	public_a_fun_link_int("clear", clear_window, 0);
	// public_a_cmd_link("secho", echo_to_screen);
	textBoxView_setup();
	activity_one_init();

	collection_fun_math_kit();
	//chart_test_demo();
	chart_file_init();
	editTextBoxView_file_init();
	init_flash();

	UART1Rx_pipe = new_input_device("uart1Rx");
	UART1Tx_pipe = new_output_device("uart1Tx", &huart1, UART_TX_Pipe_line);

	UART2Rx_pipe = new_input_device("uart2Rx");
	UART2Tx_pipe = new_output_device("uart2Tx", &huart2, UART_TX_Pipe_line);

	UART3Rx_pipe = new_input_device("uart2Rx");
	UART3Tx_pipe = new_output_device("uart2Tx", &huart2, UART_TX_Pipe_line);

	// addTask_(rx_monitor);
}

osThreadId_t touch_manager_handle;
extern osThreadId_t startupTaskHandle;
void startup(void const *argument)
{
	lily_init();
	init_core();
	osThreadAttr_t worker_att = {
		.name = "worker",
		.priority = (osPriority_t)osPriorityAboveNormal2,
		.stack_size = 128 * 4};

	// osThreadAttr_t idle_att = {
	// 	.name = "idle",
	// 	.priority = (osPriority_t)osPriorityIdle,
	// 	.stack_size = 128 * 4};

	// worker = osThreadNew(work, NULL, &worker_att);
	worker_att.name = "touchs",
	worker_att.priority = osPriorityAboveNormal4;
	touch_manager_handle = osThreadNew(touch_manager, NULL, &worker_att);
	// idler = osThreadNew(idle_fun, NULL, &idle_att);
	vTaskDelete(startupTaskHandle);

	// osThreadDef(1, task_pool, osPriorityAboveNormal, 0, 128);
	// taskpoolHandle = osThreadCreate(osThread(taskpool), NULL);
}

float millisf()
{
	extern TIM_HandleTypeDef htim1;
	static float ms;
	ms = ((unsigned int)(htim1.Instance->CNT)) / 1000.0f;
	ms += millis();
	return ms;
}
//Lily thread enter here

void Lily_runs(void *argument)
{
	//	lily_init();
	typedef void (*delay_fun)(unsigned int);
	lily_Delay = (delay_fun)osDelay;
	// lily_out = print; // sends;
	lily_millis = millis;
	//	int i;
	// public_a_var_ref("busy", &tim_c, 'd');
	// public_a_fun_link_int("ad", adc_times, 1);
	// public_a_fun_link_n("on", start_adc, 0);
	// int *c = &(htim1.Instance->CNT);

	//int last = 0;
	while (1)
	{
		if (front != rear)
		{
			if (tasks[front])
			{
				taskENTER_CRITICAL();
				if (tasks[front]() == 1)
				{
					addTask_(tasks[front]);
				}
				taskEXIT_CRITICAL();
			}
			else
			{
				// print("null ptr");
			}

			if (++front == Tasks_LEN)
				front = 0;
		}
		// osDelay(1);
	}
}

int x_sends = 0;
int y_sends = Window_pos_y;

// sends via UART
void sends(char *msg)
{
#ifdef in_debug
	static char new_line[] = "\r\n";
	char *p = dma_now_write_at ? dma_tx1 : dma_tx2;

	for (; *msg != '\0' && dma_now_count < dma_buffer_len; msg++)
	{
		if (*msg == '\n')
		{
			p[dma_now_count++] = *new_line;
			p[dma_now_count++] = new_line[1];
			// HAL_UART_Transmit(&huart1, (uint8_t *)new_line, 2, 10);
			continue;
		}
		// if (*msg == '\a')
		// {
		// 	beep(2000.0f, 0.1f);
		// 	continue;
		// }
		p[dma_now_count++] = *msg;
		// HAL_UART_Transmit(&huart1, (uint8_t *)msg, 1, 10);
	}
	if (dma_send_done)
	{
		HAL_UART_Transmit_DMA(&huart1, (uint8_t *)(dma_now_write_at ? dma_tx1 : dma_tx2), dma_now_count);
		dma_now_write_at = !dma_now_write_at;
		dma_now_count = 0;
		dma_send_done = 0;
	}
	// buffer overflow, send the following data
	if (dma_now_count >= dma_buffer_len)
	{
		while (dma_send_done == 0)
		{
			//			osDelay(1);
		}
		sends(msg);
		// HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), 100);
	}

#else

#endif
	//	sends_lock = 0;
}
// print to screen
// void print(char *msg)
// {
// 	textBoxView_addString(boxView, msg);
// 	juli_show_ui(boxView_ui, ByPass);
// 	return;
// 	if (screen_lock)
// 		return;
// 	for (; *msg != '\0'; msg++)
// 	{
// 		// if (*msg == '\n')
// 		// {
// 		// 	if (x_sends < 480)
// 		// 	{
// 		// 		LCD_fill_with(x_sends, y_sends, 480 - x_sends, 24, BACK_COLOR);
// 		// 	}
// 		// 	y_sends += 24;
// 		// 	x_sends = 0;
// 		// 	if (y_sends >= Window_pos_y + Window_size_h)
// 		// 	{
// 		// 		y_sends = Window_pos_y;
// 		// 	}
// 		// 	continue;
// 		// }
// 		// if (*msg == '\a')
// 		// {
// 		// 	continue;
// 		// }
// 		// LCD_putcAt(x_sends, y_sends, *msg);
// 		// x_sends += 12;
// 		// if (x_sends >= 480)
// 		// {
// 		// 	y_sends += 24;
// 		// 	if (y_sends >= Window_pos_y + Window_size_h)
// 		// 	{
// 		// 		y_sends = Window_pos_y;
// 		// 	}
// 		// }
// 		putcs(*msg);
// 	}
// }
// void putcs(char m)
// {
// 	if (screen_lock)
// 		return;
// 	if (m == '\n')
// 	{
// 		if (x_sends < 480)
// 		{
// 			LCD_fill_with(x_sends, y_sends, 480 - x_sends, 24, BACK_COLOR);
// 		}
// 		y_sends += 24;
// 		x_sends = 0;
// 		if (y_sends >= Window_pos_y + Window_size_h)
// 		{
// 			clear_window();
// 			y_sends = Window_pos_y;
// 		}
// 		return;
// 	}
// 	if (m == '\a')
// 	{
// 		beep(2000.0f, 0.1f);
// 		return;
// 	}
// 	LCD_putcAt(x_sends, y_sends, m);
// 	x_sends += 12;
// 	if (x_sends >= 480)
// 	{
// 		y_sends += 24;
// 		if (y_sends >= Window_pos_y + Window_size_h)
// 		{
// 			y_sends = Window_pos_y;
// 			clear_window();
// 		}
// 	}
// }

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	dma_send_done = 1;
	if (dma_now_count) //have date need to send
	{
		HAL_UART_Transmit_DMA(&huart1, dma_now_write_at ? dma_tx1 : dma_tx2, dma_now_count);
		dma_now_write_at = !dma_now_write_at; //change to another buffer to write
		dma_now_count = 0;					  //clear count
		dma_send_done = 0;					  //wait for sending done
	}
}

#define start_work 0x010000
void work(void *arg)
{
}
void idle_fun()
{
	while (1)
	{
	}
}
void touch_manager(void *arg)
{

	// ref 1.2V
	juli_show_up();
	public_a_timer(power_off_timer, Second(power_off_peroid));
	public_a_var_ref("stm", &power_off_peroid, 'd');
	Presse_Statue ste = None;
	// int x, y;
	while (1)
	{
		ste = TP_Scan_statue();
		if (ste == None)
		{
			osDelay(10);
			continue;
		}
		if (need_power_off == 2)
		{
			LCD_SSD_BackLightSet(27);
		}
		need_power_off = 0;
		// taskENTER_CRITICAL();
		// taskEXIT_CRITICAL();
		taskENTER_CRITICAL();
		int d = juli_boardcast_event(tp_dev.x[0], tp_dev.y[0], ste);
		taskEXIT_CRITICAL();
		osDelay(d);
	}
}

//-------------------
int gpio_cmd(int nargin, char **arg)
{
	// 8
	if (nargin < 2)
		return -1;
	GPIO_TypeDef *port;
	uint16_t pin = 1;
	//get port
	arg[1][0] = toLower(arg[1][0]);
	assert_msg(('a' <= arg[1][0] && arg[1][0] <= 'i'), "bad port");

	int n = arg[1][0] - 'a';
	port = (GPIO_TypeDef *)(GPIOA_BASE + (GPIOB_BASE - GPIOA_BASE) * n);
	// get pin
	int now = 1;
	if (arg[now][1] != '\0') //like a11
	{
		if (!str_is_numeric(arg[1] + 1))
		{
			lily_error_msg = "bad argument\n";
			return -4;
		}
		n = atoi(arg[now] + 1);
	}
	else
	{
		now = 2;
		n = atoi(arg[now]);
	}

	if (n > 15)
		return -3;
	pin <<= n;
	now++;
	if (nargin > now)
	{
		switch (arg[now][0])
		{
		case '0':
			HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET);
			break;
		case '1':
			HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET);
			break;
		default:
			HAL_GPIO_TogglePin(port, pin);
			break;
		}
	}
	else
	{
		GPIO_PinState s = HAL_GPIO_ReadPin(port, pin); //colum read
		if (s == GPIO_PIN_SET)
			lily_out("1\n");
		else
			lily_out("0\n");
	}
	return 0;
}

// int echo_to_screen(int n, char **arg)
// {
// 	int now = 1;
// 	if (strcmp("secho", arg[0]) != 0)
// 	{
// 		now = 0;
// 	}
// 	//int index;
// 	for (; now < n; now++)
// 	{
// 		print(arg[now]);
// 		if (now < n - 1)
// 			print(" ");
// 		else
// 			print("\n");
// 	}
// 	return 0;
// }

int blink()
{
	HAL_GPIO_TogglePin(LED0_n_GPIO_Port, LED0_n_Pin);
	return 0;
}

float ad_times(int n)
{
	int i;
	int sum = 0;
	// taskENTER_CRITICAL();
	for (i = 0; i < n; i++)
	{
		HAL_ADC_Start(&hadc1);
		HAL_ADC_PollForConversion(&hadc1, 100);
		int d = HAL_ADC_GetValue(&hadc1);
		sum += d;
	}
	// taskEXIT_CRITICAL();
	float d = sum / n;
	return d * 3.3f / 0xfff;
}

// int spi_n;
// int spi_frame_count;
// void start_spi_rec()
// {
// 	const int len = 360 * 360 * 2 / 4;
// 	if (!video_mode)
// 		return;
// 	LCD_Set_Window(Window_pox_x, Window_pos_y, Window_size_w, Window_size_h);
// 	screen_lock = 4;
// 	// video_mode = 1;
// 	(LCD->LCD_REG = lcddev.wramcmd);
// 	HAL_SPI_Receive_DMA(&hspi1, (uint8_t *)&(LCD->LCD_RAM), len);
// }
// int force_stop_spi_dma()
// {
// 	if (video_mode)
// 		return 0;
// 	if (screen_lock)
// 	{
// 		HAL_SPI_DMAStop(&hspi1);
// 		screen_lock = 0; //unlock
// 	}
// 	return 0;
// }
// void stop_spi()
// {
// 	HAL_SPI_DMAStop(&hspi1);
// 	// if (video_mode)
// 	// {
// 	// 	create_or_change_quick_timer_count(force_stop_spi_dma, Second(0.3f));
// 	// 	// video_mode = 0;
// 	// }
// 	// video_mode = 0;
// 	// if (HAL_SPI_DMAStop(&hspi1) == HAL_OK)
// 	// 	screen_lock = 0;
// 	// else
// 	// {
// 	// 	lily_out("failed stop dma\nforce unlock after 0.3s\n");
// 	// 	//如果当前图片未写完，在0.3s后释放屏幕锁， 弃用
// 	// }
// }
// void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
// {
// 	spi_frame_count++;
// 	screen_lock--;
// 	if (video_mode && screen_lock <= 0)
// 	{
// 		screen_lock = 0;
// 		LCD_Set_Window(Window_pox_x, Window_pos_y, Window_size_w, Window_size_h);
// 		(LCD->LCD_REG = lcddev.wramcmd);
// 		// HAL_SPI_DMAStop(&hspi1);
// 		// screen_lock = 0;
// 	}
// 	else if (screen_lock <= 0) // maybe caused by force stop dma
// 	{
// 		screen_lock = 0;
// 		spi_frame_count--;
// 		HAL_SPI_DMAStop(&hspi1);
// 	}
// }

int beep_timer()
{
	TIM2->CCR1 = 0;
	// __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 0);
	return 0;
}
void beep(float freq, float sec)
{
	static int last_arr = 0;
	beep_max_volume = 2000000.0f / freq - 1;
	if (beep_max_volume < 99)
	{
		beep_max_volume = 99;
	}
	int arr = beep_max_volume; // auto reolad reg
	if (arr != last_arr)
	{
		// HAL_TIM_Base_Stop(&htim2);
		// HAL_TIM_PWM_Stop(&htim2,TIM_CHANNEL_1);
		TIM2->ARR = arr;
		TIM2->CNT = 0;
		// HAL_TIM_Base_Start(&htim2);
		last_arr = arr;
	}
	int ccr = arr * beep_volume;
	TIM2->CCR1 = ccr;
	// __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 50);
	create_or_change_quick_timer_count(beep_timer, Second(sec));
}

// void clear_window()
// {
// 	x_sends = 0;
// 	y_sends = Window_pos_y;
// 	if (screen_lock)
// 		return;
// 	taskENTER_CRITICAL();
// 	LCD_fill_with(0, Window_pos_y, 480, Window_size_h + 8, BACK_COLOR);
// 	taskEXIT_CRITICAL();
// }

// int rx_monitor()
// {
// 	static char rx_back = 0;
// 	while (ri != rx_back)
// 	{
// 		putcs(rx[rx_back]);
// 		rx_back++;
// 	}
// 	return 1;
// }

// void pushc(char c)
// {
// 	static int in_block = 0;
// 	static int bar_x = 0, to_bar = 0;
// 	if (c == '#')
// 	{
// 		in_block = 1;
// 		return;
// 	}
// 	else if (c == '^')
// 	{
// 		to_bar = 1;
// 		bar_x = 0;
// 		return;
// 	}
// 	if (in_block)
// 	{
// 		if (c == '\n')
// 		{
// 			in_block = 0;
// 		}
// 		lily_in(c);
// 	}
// 	else if (to_bar)
// 	{
// 		if (c == '\n')
// 		{
// 			to_bar = 0;
// 			LCD_fill_with(bar_x, 0, 480 - bar_x, 24, BACK_COLOR);
// 			return;
// 		}
// 		LCD_putcAt(bar_x, 0, c);
// 		bar_x += 12;
// 		if (bar_x >= 480)
// 		{
// 			bar_x = 0;
// 		}
// 	}
// 	else
// 	{
// 		textBoxView_addChar(boxView, c);
// 		juli_show_ui(boxView_ui, ByPass);
// 		// putcs(c);
// 	}
// }

int FlashErase(void *p)
{
	/* Base address of Sector 6, 128 Kbytes  */
	// #define ADDR_FLASH_SECTOR_1 ((uint32_t)0x3f800) /* Base address of Sector 7, 128 Kbytes  */

	int pa = p;
	int i;
	for (i = 0; i < 7; i++)
	{
		int a = ADDR_OF_BANK(i);
		int b = ADDR_OF_BANK(i + 1);
		if (a >= pa && pa > b)
		{
			// memset(emu_flash_0[i], 0xff, ChunkSize);
			break;
		}
	}
	if (i == 7)
	{
		return -1;
	}

	FLASH_EraseInitTypeDef flash_erase;
	// FLASH_BASE
	//clear sector 7
	flash_erase.Sector = 11 - i; // FLASH_SECTOR_7;
	flash_erase.TypeErase = FLASH_TYPEERASE_SECTORS;
	flash_erase.VoltageRange = FLASH_VOLTAGE_RANGE_3;
	flash_erase.NbSectors = 1;
	// flash_erase.
	uint32_t error;
	HAL_FLASH_Unlock();
	HAL_FLASHEx_Erase(&flash_erase, &error);
	if (FLASH_WaitForLastOperation(1000) != HAL_OK)
	{
		HAL_FLASH_Lock();
		return -1;
	}
	return 0;
}

int FlashProgram(int *val, int addr, int size_byte)
{
	if (size_byte % 4)
		return -1;
	size_byte /= 4;
	int i;
	for (i = 0; i < size_byte; i++, val++, addr += 4)
	{
		if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, *val) != HAL_OK)
		{
			HAL_FLASH_Lock();
			return -1;
		}
	}
	return 0;
}

void lock_flash()
{
	HAL_FLASH_Lock();
}

int power_off_timer()
{
	if (need_power_off == 0)
	{
		need_power_off = 1;
		return 0;
	}
	if (need_power_off == 1)
	{
		LCD_SSD_BackLightSet(0);
		need_power_off = 2;
	}
	int i = find_timer(power_off_timer);
	Li_timer ts = list_content(lily_timers, Li_timer_t);
	ts[i].period = Second(power_off_peroid);

	return 0;
}

void *UART_TX_Pipe_line(void *arg, char *d, int n)
{
	HAL_UART_Transmit(arg, d, n, 100);
	return NULL;
}
void UART_RX_pipe_release_date(Pipe p, char c) // 1 byte
{
	pipe_release_data(p, &c, 1);
}

void UART_SetConfig(UART_HandleTypeDef *huart);
int cmd_uart_change_bound_rate(int n, char *arg[])
{
	if (n < 2)
	{
		li_error("usage:uart n bRate", -1);
	}
	assert_msg(isD(arg[1][0]), "not a num");
	int ind = arg[1][0] - '0';
	assert_msg(ind > 0 && ind < 4, "index er");
	UART_HandleTypeDef *hands[] = {&huart1, &huart2, &huart3};
	if (n > 2)
	{
		assert_msg(str_is_numeric(arg[2]), "not a number");
		int rate = atoi(arg[2]);
		hands[ind]->Init.BaudRate = rate;
		UART_SetConfig(hands[ind]);
	}
	else
	{
		int rate = hands[ind]->Init.BaudRate;
		sprintf(tx, "%d\n", rate);
		lily_out(tx);
		return rate;
	}

	return 0;
}